#include "CRangedEnemy.h"
#include "../Game States/CGamePlayState.h"

#include "../SGD Wrappers/CSGD_TextureManager.h"
#include "../SGD Wrappers/CSGD_Direct3D.h"
#include "../Game States/CGamePlayState.h"
#include "../Core/MessageSystem.h"
#include "../Core/VIN_EventSystem.h"
#include "../managers/vin_soundmanager.h"
#include "CRock.h"

enum EAnimationState { ENEMY_IDLE, ENEMY_ATTACKING };

CRangedEnemy::CRangedEnemy(unsigned int type)
{
	SetAlive(true);
	SetPassive(false);
	SetDistanceToPlayer(Vector2D(0.0f, 0.0f));
	SetHP(50);
	SetPower(20);
	treebucket = false;
	bouldershot = false;
	
	color = -1;
	currAnimation = ENEMY_IDLE;

	enemyType = type;

	if(enemyType == ENEMY_ARCHER)
	{
		Load("resources/XML/Elf_Animation.xml");
		scale = 1.0f;
		SetWidth(20);
		SetHeight(40);
	}
	else if(enemyType == FRIENDLY_ARCHER)
	{
		Load("resources/XML/Elf_Animation.xml");
		currAnimation = ENEMY_ATTACKING;
		scale = 1.0f;
		SetWidth(20);
		SetHeight(40);
	}
	else if(enemyType == ENEMY_CATAPULT)
	{
		Load("resources/XML/Catapult_Animation.xml");
		scale = 0.8f;
		SetWidth(80);
		SetHeight(46);
	}
	else if(enemyType == ENEMY_TREBUCHET)
	{
		Load("resources/XML/Catapult_Animation.xml");
		scale = 0.9f;
		SetWidth(80);
		SetHeight(46);
	}

	attackTimer = 1.0f;

	deathTimer = 1.3f + (GetGroundPt()*0.007f);
	readyToDie = false;

	curVelocity = GetVelX();
	SetType(OBJ_ENEMY);
	vAnimation[currAnimation].Play();
	
	VIN_EventSystem::GetInstance()->ResgisterClient("Ballista", this);
}

CRangedEnemy::~CRangedEnemy()
{	
	if(!vAnimation.empty())
	{
		vAnimation.clear();
	}
	
	VIN_EventSystem::GetInstance()->UnregisterClient("Ballista", this);
}

RECT CRangedEnemy::GetHealthRect()
{
	RECT temp;
	if(currAnimation < (int)vAnimation.size())
	{
		temp.left  = (int)GetPosX() + vAnimation[currAnimation].GetHealthFrame().left;
		temp.right = (int)GetPosX() + vAnimation[currAnimation].GetHealthFrame().right;
		temp.top   = (int)GetPosY() + vAnimation[currAnimation].GetHealthFrame().top;
		temp.bottom= (int)GetPosY() + vAnimation[currAnimation].GetHealthFrame().bottom;
		//if(flip)
		//{
		//	temp.left = (int)GetPosX() - vAnimation[currAnimation].GetAttackFrame().right;
		//	temp.right =(int)GetPosX() - vAnimation[currAnimation].GetAttackFrame().left;
		//}
		return temp;
	}
	else
	{
		SetRect(&temp,0,0,0,0);
		return temp;
	}
}

void CRangedEnemy::Attack()
{
	// TODO Start Shooting animation
	// If the animation completes substract from player's health by GetPower()
	// The attack must have a cooldown of at least 2 seconds
	// Play Shooting sound

}

void CRangedEnemy::HurtMe()
{ 
	SetHP(GetHP() - ( RandInt(20, 30)));
	if(GetHP() <= 0)
	{
		// TODO: Kill the enemy and increase the player's money by a random amount
		// Play enemy death sound
	}
}

void CRangedEnemy::Update( float fElapsedTime)
{
	// TODO Stay within a good range of the player, walking towards or away him as need be.
	attackTimer -= fElapsedTime;

	if(readyToDie)
		deathTimer -= fElapsedTime;

	if(deathTimer <= 0)
	{
		SetHP(0);
	}

	//if(GetHP() <= 0)
	//{
	//	MessageSystem::GetInstance()->SendNewMessage(new CDestroyObjectMessage(this, 0));
	//	CGamePlayState::GetInstance()->SetDeadEnemies(CGamePlayState::GetInstance()->GetDeadEnemies() + 1);
	//	MessageSystem::GetInstance()->SendNewMessage(new CCreateMoneyBagMessage(GetPosX(), GetPosY(), CGamePlayState::GetInstance()->GetWaveCount()));
	//}

	//CBaseObject::Update(fElapsedTime);		
	
	if(enemyType != FRIENDLY_ARCHER)
	{
		CBaseEnemy::Update(fElapsedTime);
	}
	

	if(!GetLanded())
	{
		currAnimation = ENEMY_IDLE;
		vAnimation[currAnimation].Update(fElapsedTime * 5);		
		vAnimation[currAnimation].Play();
	}
	else
	{
		if(enemyType != FRIENDLY_ARCHER)
		{
			if(abs(GetPosX() - CGamePlayState::GetInstance()->GetPlayer()->GetPosX()) <= 170)
			{
				SetVelX(0);
				currAnimation = ENEMY_ATTACKING;
				VIN_SoundManager::GetInstance()->PlayShot();
			}
			else
			{
				SetVelX(50*GetSpeed());
				currAnimation = ENEMY_IDLE;
			}
		}

		////if(enemyType = ENEMY_CATAPULT)
		//{
		//	vAnimation[currAnimation].Update(fElapsedTime);
		//	vAnimation[currAnimation].Play();
		//}
		////else

		if(bouldershot)
		{
			static float bouldertimer = 0.0f;
			bouldertimer += fElapsedTime;
			if(bouldertimer >= 3.9f)
			{
				CGamePlayState::GetInstance()->GetPlayer()->SetHP(CGamePlayState::GetInstance()->GetPlayer()->GetHP() - (float)GetPower());
				bouldertimer = 0.0f;
				bouldershot = false;
			}
		}
		if(treebucket)
		{
			static float treebuckettime = 0.0f;
			treebuckettime += fElapsedTime;
			if(treebuckettime >= 4.3f)
			{
				CGamePlayState::GetInstance()->GetPlayer()->SetHP(CGamePlayState::GetInstance()->GetPlayer()->GetHP() - (float)GetPower());
				treebuckettime = 0.0f;
				treebucket = false;
			}
		}
		if(currAnimation == ENEMY_ATTACKING)
		{
			if(vAnimation[currAnimation].GetCurFrame() == vAnimation[currAnimation].GetMaxFrames() - 1)
			{					
				if(attackTimer < 0.0f)
				{
					vAnimation[currAnimation].Update(fElapsedTime);
					vAnimation[currAnimation].SetCurFrame(0);
					vAnimation[currAnimation].Play();
					if(enemyType == ENEMY_CATAPULT)
					{
						attackTimer = 5.f; 
						MessageSystem::GetInstance()->SendNewMessage(new CCreateProjectileMessage(GetPosX() - 100.0f, GetPosY() - 100.0f, 100.0f, -200.0f, 1));
						bouldershot = true;
					}
					else if(enemyType == ENEMY_ARCHER)
					{
						attackTimer = 1.0f;
						MessageSystem::GetInstance()->SendNewMessage(new CCreateProjectileMessage(GetPosX() + 32.0f, GetPosY() - 32.0f, 200.0f, -100.0f, 0));
						CGamePlayState::GetInstance()->GetPlayer()->SetHP(CGamePlayState::GetInstance()->GetPlayer()->GetHP() - (float)GetPower());

					}
					else if(enemyType == FRIENDLY_ARCHER)
					{
						MessageSystem::GetInstance()->SendNewMessage(new CCreateProjectileMessage(GetPosX(), GetPosY() - 32.0f, -200.0f - rand()%50, -100.0f - rand()%50, 2));
						attackTimer = (float)(rand()%10)*0.1f;
					}
					else
					{
						attackTimer = 8.0f;
						MessageSystem::GetInstance()->SendNewMessage(new CCreateProjectileMessage(GetPosX() - 100.0f, GetPosY() - 100.0f, 75.0f, -300.0f, 1));
						treebucket = true;
					}						
				}
				else
				{
					vAnimation[currAnimation].Stop();
				}
			}
			else
			{
				vAnimation[currAnimation].Update(fElapsedTime);
				vAnimation[currAnimation].Play();
			}				
		}
		else
		{
			vAnimation[currAnimation].Update(fElapsedTime);
			vAnimation[currAnimation].Play();
		}
		
	}
}

void CRangedEnemy::Render()
{
	CSGD_TextureManager* pTM  = CSGD_TextureManager::GetInstance();
	CSGD_Direct3D* d3d  = CSGD_Direct3D::GetInstance();

	if(enemyType != FRIENDLY_ARCHER)
		CBaseEnemy::Render();

	//d3d->DrawRect(GetHealthRect(), 255, 0, 0);
	vAnimation[currAnimation].Render(GetPosX() , GetPosY() , flip, scale, color);

	d3d->GetSprite()->Flush();


}

bool CRangedEnemy::CheckCollision(IBaseInterface *pBase)
{
	if(CBaseEnemy::CheckCollision(pBase))
	{
		//currAnimation = ENEMY_ATTACKING;
	}
	return false;
}


bool CRangedEnemy::Load( const char* AnimInfo)
{
	int tempID;

	TiXmlDocument doc;

	if(doc.LoadFile(AnimInfo) == false)
		return false;

	TiXmlElement* Root = doc.RootElement();
	if(Root == NULL)
		return false;

	TiXmlElement* NumAnim = Root->FirstChildElement("xNumOfAnim");
	int count = atoi(NumAnim->GetText());

	TiXmlElement* ImageFile = Root->FirstChildElement("xImageFile");
	if(ImageFile)
	{
		tempID = CSGD_TextureManager::GetInstance()->LoadTexture(ImageFile->GetText());
	}

	TiXmlElement* xAnimation  = Root->FirstChildElement("xAnimation");

	while(xAnimation)
	{
		CAnimation a;

		TiXmlElement* NumFrame = xAnimation->FirstChildElement("xNumOfFrames");
		int fcount = atoi(NumFrame->GetText());

		TiXmlElement* looping = xAnimation->FirstChildElement("xLooping");\
		a.SetIsLooping((bool)(atoi(looping->GetText())));

		TiXmlElement* AnimSpd = xAnimation->FirstChildElement("xAnimSpd");
		a.SetSpeed((float)( atoi(AnimSpd->GetText())));

		TiXmlElement* xFrame = xAnimation->FirstChildElement("xFrame");

		Frame temp;
		temp.fTime = 0;
		temp.ptAnchor.x = 0;
		temp.ptAnchor.y = 0;

		SetRect(&temp.rAttack,0,0,0,0);
		SetRect(&temp.rCollision,0,0,0,0);
		SetRect(&temp.rRender,0,0,0,0);

		temp.ptAnchor.x = 0;
		temp.ptAnchor.y = 0;


		while(xFrame)
		{
			TiXmlElement* xTime = xFrame->FirstChildElement("xTime");
			if(xTime)
			{
				temp.fTime =(float)( atoi(xTime->GetText()) );
			}
			TiXmlElement* FrameType = xFrame->FirstChildElement("xFrameType");
			if(FrameType)
			{
				TiXmlElement* RenderFrame = FrameType->FirstChildElement("xRenderFrame");
				if(RenderFrame)
				{
					TiXmlElement* RenderFrameX = RenderFrame->FirstChildElement("xRenderFrameX");
					if(RenderFrameX)
						temp.rRender.left =  atoi(RenderFrameX->GetText());

					TiXmlElement* RenderFrameY = RenderFrame->FirstChildElement("xRenderFrameY");
					if(RenderFrameY)
						temp.rRender.top = atoi(RenderFrameY->GetText());

					TiXmlElement* RenderFrameW = RenderFrame->FirstChildElement("xRenderFrameW");
					if(RenderFrameW)
					{
						temp.rRender.right = atoi(RenderFrameW->GetText());
						temp.rRender.right += temp.rRender.left;
					}

					TiXmlElement* RenderFrameH = RenderFrame->FirstChildElement("xRenderFrameH");
					if(RenderFrameH)
					{
						temp.rRender.bottom = atoi(RenderFrameH->GetText());
						temp.rRender.bottom += temp.rRender.top;
					}
				}

				TiXmlElement* CollisionFrame = FrameType->FirstChildElement("xCollisionFrame");
				if(CollisionFrame)
				{
					TiXmlElement* CollisionFrameX = CollisionFrame->FirstChildElement("xCollisionFrameX");
					if(CollisionFrameX)
						temp.rCollision.left = atoi(CollisionFrameX->GetText());

					TiXmlElement* CollisionFrameY = CollisionFrame->FirstChildElement("xCollisionFrameY");
					if(CollisionFrameY)
						temp.rCollision.top = atoi(CollisionFrameY->GetText());

					TiXmlElement* CollisionFrameW = CollisionFrame->FirstChildElement("xCollisionFrameW");
					if(CollisionFrameW)
						temp.rCollision.right = atoi(CollisionFrameW->GetText());

					TiXmlElement* CollisionFrameH = CollisionFrame->FirstChildElement("xCollsionFrameH");
					if(CollisionFrameH)
						temp.rCollision.bottom = atoi(CollisionFrameH->GetText());
				}

				TiXmlElement* AttackFrame = FrameType->FirstChildElement("xAttackFrame");
				if(AttackFrame)
				{
					TiXmlElement* AttackFrameX = AttackFrame->FirstChildElement("xAttackFrameX");
					if(AttackFrameX)
						temp.rAttack.left = atoi(AttackFrameX->GetText());

					TiXmlElement* AttackFrameY = AttackFrame->FirstChildElement("xAttackFrameY");
					if(AttackFrameY)
						temp.rAttack.top = atoi(AttackFrameY->GetText());

					TiXmlElement* AttackFrameW = AttackFrame->FirstChildElement("xAttackFrameW");
					if(AttackFrameW)
						temp.rAttack.right = atoi(AttackFrameW->GetText());

					TiXmlElement* AttackFrameH = AttackFrame->FirstChildElement("xAttackFrameH");
					if(AttackFrameH)
						temp.rAttack.bottom = atoi(AttackFrameH->GetText());
				}

				TiXmlElement* AnchorPoint = FrameType->FirstChildElement("xAnchorPoint");
				if(AnchorPoint)
				{
					TiXmlElement* AnchorPointX = AnchorPoint->FirstChildElement("xAnchorPointX");
					if(AnchorPointX)
					{
						int ax = atoi(AnchorPointX->GetText());
						temp.ptAnchor.x =  ax - temp.rRender.left;
					}

					TiXmlElement* AnchorPointY = AnchorPoint->FirstChildElement("xAnchorPointY");
					if(AnchorPointY)
					{
						int ay = atoi(AnchorPointY->GetText());
						temp.ptAnchor.y = ay - temp.rRender.top;
					}
				}
			}
			a.SetTimeDelay(temp.fTime);

			temp.rAttack.right +=  temp.rAttack.left;
			temp.rAttack.bottom += temp.rAttack.top;
			temp.rAttack.left -= (temp.ptAnchor.x + temp.rRender.left);
			temp.rAttack.top -= (temp.ptAnchor.y + temp.rRender.top);
			temp.rAttack.right -= (temp.ptAnchor.x + temp.rRender.left);
			temp.rAttack.bottom -=(temp.ptAnchor.y + temp.rRender.top);

			temp.rCollision.right +=  temp.rCollision.left;
			temp.rCollision.bottom += temp.rCollision.top;
			temp.rCollision.left -= (temp.ptAnchor.x + temp.rRender.left);
			temp.rCollision.top -= (temp.ptAnchor.y + temp.rRender.top);
			temp.rCollision.right -= (temp.ptAnchor.x + temp.rRender.left);
			temp.rCollision.bottom -=(temp.ptAnchor.y + temp.rRender.top);


			a.addFrame(temp);
			xFrame = xFrame->NextSiblingElement("xFrame");
		}
		a.SetImageID(tempID);
		vAnimation.push_back(a);

		xAnimation = xAnimation->NextSiblingElement("xAnimation");
	}
	return true;

}

void CRangedEnemy::HandleEvent(CEvent* pEvent)
{
	if(pEvent->GetEventID() == "Ballista")
	{
		// Destroy Enemy
		if(currAnimation == ENEMY_ATTACKING)
			readyToDie = true;
	}
}